﻿using System;
using System.Collections;
using System.Collections.Generic;

namespace Nomo.CoreModule
{
    /// <summary>
    /// 不做安全检测的列表。
    /// </summary>
    /// <typeparam name="T">成员的类型。</typeparam>
    public class UnsafeList<T> : IList<T>
    {
        private static readonly T[] EmptyArray = new T[0];
        private                 T[] _items;
        private                 int _size;

        /// <summary>
        /// 初始化容量为 0 的不安全列表。
        /// </summary>
        public UnsafeList()
        {
            _items = EmptyArray;
        }

        /// <summary>
        /// 初始化拥有指定初始容量的不安全列表。
        /// </summary>
        /// <param name="capacity"></param>
        public UnsafeList(int capacity)
        {
            _items = capacity == 0 ? EmptyArray : new T[capacity];
        }

        /// <summary>
        /// 初始化包含了指定集合里的所有成员的不安全列表。
        /// </summary>
        /// <param name="enumerable">集合。</param>
        public UnsafeList(IEnumerable<T> enumerable)
        {
            if (enumerable is ICollection<T> collectionElements)
            {
                var count = collectionElements.Count;
                if (count == 0)
                {
                    _items = EmptyArray;
                }
                else
                {
                    _items = new T[count];
                    collectionElements.CopyTo(_items, 0);
                    _size = count;
                }
            }
            else
            {
                _size  = 0;
                _items = EmptyArray;
                foreach (var element in enumerable)
                {
                    ((ICollection<T>) this).Add(element);
                }
            }
        }

        /// <inheritdoc />
        public T this[int index] { get => _items[index]; set => _items[index] = value; }

        /// <inheritdoc />
        public int Count => _size;

        /// <inheritdoc />
        public bool IsReadOnly => false;

        /// <summary>
        /// 返回访问 <see cref="UnsafeList{T}"/> 的枚举数。
        /// </summary>
        /// <returns>访问 <see cref="UnsafeList{T}"/> 的枚举数。</returns>
        public Enumerator GetEnumerator()
        {
            return new Enumerator(this);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return new Enumerator(this);
        }

        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            return new Enumerator(this);
        }

        private void EnsureCapacity(int min)
        {
            if (_items.Length >= min)
            {
                return;
            }
            var num = _items.Length == 0 ? 4 : _items.Length << 1;
            num = Math.Min(num, 1                            << 30);
            num = Math.Max(num, min);
            var objArray = new T[num];
            if (_size > 0)
            {
                Array.Copy(_items, 0, objArray, 0, _size);
            }
            _items = objArray;
        }

        /// <inheritdoc />
        public void Add(T item)
        {
            if (_size == _items.Length)
            {
                EnsureCapacity(_size + 1);
            }
            _items[_size++] = item;
        }

        /// <inheritdoc />
        public void Insert(int index, T item)
        {
            if (_size == _items.Length)
            {
                EnsureCapacity(_size + 1);
            }
            if (index < _size)
            {
                Array.Copy(_items, index, _items, index + 1, _size - index);
            }
            _items[index] = item;
            _size++;
        }

        /// <inheritdoc />
        public bool Remove(T item)
        {
            var index = IndexOf(item);
            if (index < 0)
            {
                return false;
            }
            RemoveAt(index);
            return true;
        }

        /// <inheritdoc />
        public void RemoveAt(int index)
        {
            _size--;
            if (index < _size)
            {
                Array.Copy(_items, index + 1, _items, index, _size - index);
                _items[_size] = default;
            }
        }

        /// <inheritdoc />
        public bool Contains(T item)
        {
            if (item == null)
            {
                for (var i = 0; i < _size; i++)
                {
                    if (_items[i] == null)
                    {
                        return true;
                    }
                }
                return false;
            }

            var equalityComparer = EqualityComparer<T>.Default;
            for (var i = 0; i < _size; i++)
            {
                if (equalityComparer.Equals(_items[i], item))
                {
                    return true;
                }
            }
            return false;
        }

        /// <inheritdoc />
        public int IndexOf(T item)
        {
            return Array.IndexOf(_items, item, 0, _size);
        }

        /// <inheritdoc />
        public void CopyTo(T[] array, int arrayIndex)
        {
            Array.Copy(_items, 0, array, arrayIndex, _size);
        }

        /// <inheritdoc />
        public void Clear()
        {
            if (_size > 0)
            {
                Array.Clear(_items, 0, _size);
                _size = 0;
            }
        }

        /// <summary>
        /// 用于枚举 <see cref="UnsafeList{T}"/> 成员的枚举数。
        /// </summary>
        public struct Enumerator : IEnumerator<T>
        {
            private readonly UnsafeList<T> _list;
            private          int           _index;

            internal Enumerator(UnsafeList<T> list)
            {
                _list   = list;
                _index  = 0;
                Current = default;
            }

            /// <inheritdoc />
            public T Current { get; private set; }

            object IEnumerator.Current => Current;

            void IDisposable.Dispose() { }

            /// <inheritdoc />
            public bool MoveNext()
            {
                if (_index >= _list._size)
                {
                    Current = default;
                    _index  = _list._size + 1;
                    return false;
                }

                Current = _list._items[_index++];
                return true;
            }

            /// <inheritdoc />
            public void Reset()
            {
                _index  = 0;
                Current = default;
            }
        }
    }
}
